﻿using System;
using System.Net;
using System.Configuration;
using System.Linq;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Text;


using System.IO.IsolatedStorage;
using System.Collections;
using System.Windows.Media.Imaging;
using System.Runtime.Serialization;

namespace VISUALFINDR
{
    //String responseString = "{\"d\":{ \"id\" : \"4324\",\"status\":\"\" } }";
    [DataContract]
    public class UploadResponseDictionary
    {
        [DataMember]
        public UploadResponseObject d { get; set; }
    }

    [DataContract]
    public class UploadResponseObject
    {
        [DataMember]
        public String id { get; set; }
        [DataMember]
        public String status { get; set; }
    }

    public class UploadUpdateState
    {
        public HttpWebRequest AsyncRequest { get; set; }
        public HttpWebResponse AsyncResponse { get; set; }
    }

    public class UploadController
    {
        public String LatestResponse;
        public String boundary;
        Dictionary<String, String> uploadData;
        byte[] ImageData;

        public void Reset()
        {
            LatestResponse = "";
            boundary = "";
            uploadData = new Dictionary<String, String>();
            ImageData = null;
        }

        static public string DeviceHash(string deviceId)
        {
            string t = deviceId + "WkUJvUWurBF41YYtd4xVEO";

            //MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            //string hash = BitConverter.ToString(md5.ComputeHash(Encoding.Default.GetBytes(t)));
            string hash = MD5Core.GetHashString(t);
            return hash.Replace("-", "").ToLower();
        }

        // This has worked in the past
        /*
        //Obtain a virtual store for application
            //IsolatedStorageFile myStore = IsolatedStorageFile.GetUserStoreForApplication();
            //StreamResourceInfo sr = Application.GetResourceStream(new Uri("UploadTestImage.jpg", UriKind.Relative));
            //Stream inputfilestream = sr.Stream;
            //byte[] InputFileData = new byte[inputfilestream.Length];
            //inputfilestream.Read(InputFileData, 0, System.Convert.ToInt32(inputfilestream.Length));
            //uploadController.UploadImagePhone(InputFileData);
         */

        public void UploadImagePhone(byte[] ImageDataInput)
        {
            Reset();

            String publicKey = SettingsController.PublicKey();
            String assetClass = SettingsController.AssetClass();
            String deviceType = SettingsController.DeviceType();
            String deviceId = SettingsController.DeviceId();

            String deviceToken = DeviceHash(deviceId);
            String versionNumber = "Web-0.4";

            // TODO: FILL IN ACTUAL LOCATION
            String latitude = "0.0";
            String longitude = "0.0";

            UriBuilder fullUri = new UriBuilder(SettingsController.UploadURL());

            // initialize a new WebRequest
            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(fullUri.Uri);
            webRequest.Method = "POST";

            boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
            webRequest.ContentType = "multipart/form-data; boundary=" + boundary;

            // Prepare Data
            uploadData.Add("deviceType", deviceType);
            uploadData.Add("deviceId", deviceId);
            uploadData.Add("deviceToken", deviceToken);
            uploadData.Add("versionNumber", versionNumber);
            uploadData.Add("latitude", latitude);
            uploadData.Add("longitude", longitude);
            uploadData.Add("publicKey", publicKey);
            uploadData.Add("assetClass", assetClass);

            ImageData = ImageDataInput;

            // set up the state object for the async request
            UploadUpdateState uploadState = new UploadUpdateState();
            uploadState.AsyncRequest = webRequest;

            webRequest.BeginGetRequestStream(new AsyncCallback(HandleUploadImageReqest), uploadState);
        }

        public void HandleUploadImageReqest(IAsyncResult asyncResult)
        {
            // get the state information
            UploadUpdateState uploadState = (UploadUpdateState)asyncResult.AsyncState;
            HttpWebRequest webRequest = (HttpWebRequest)uploadState.AsyncRequest;

            // Add post data
            using (StreamWriter writer = new StreamWriter(webRequest.EndGetRequestStream(asyncResult)))
            {
                
                byte[] boundarybytes = System.Text.Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");

                string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
                string formdataTemplate2 = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{0}\"\r\nContent-Type: {1}\r\n\r\n";

                // add image first
                Stream rs = writer.BaseStream;

                //MemoryStream ms = new MemoryStream();
                //image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                //byte[] outputdata = ms.GetBuffer();

                rs.Write(boundarybytes, 0, boundarybytes.Length);
                string formitem1 = string.Format(formdataTemplate2, "image", "application/octet-stream");
                byte[] formitembytes1 = System.Text.Encoding.UTF8.GetBytes(formitem1);
                rs.Write(formitembytes1, 0, formitembytes1.Length);
                rs.Write(ImageData, 0, ImageData.Length);

                // then all other stuff
                foreach (string key in uploadData.Keys)
                {
                    rs.Write(boundarybytes, 0, boundarybytes.Length);
                    string formitem = string.Format(formdataTemplate, key, uploadData[key]);
                    byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
                    rs.Write(formitembytes, 0, formitembytes.Length);
                }
                rs.Write(boundarybytes, 0, boundarybytes.Length);
                rs.Close();
            }

            // start the asynchronous request
            webRequest.BeginGetResponse(new AsyncCallback(HandleUploadResponse),
                uploadState);
        }

        /// <summary>
        /// Handle the information returned from the async request
        /// </summary>
        /// <param name="asyncResult"></param>
        private void HandleUploadResponse(IAsyncResult asyncResult)
        {
            // get the state information
            UploadUpdateState uploadUpdateState = (UploadUpdateState)asyncResult.AsyncState;
            HttpWebRequest uploadRequest = (HttpWebRequest)uploadUpdateState.AsyncRequest;

            // end the async request
            try
            {
                uploadUpdateState.AsyncResponse = (HttpWebResponse)uploadRequest.EndGetResponse(asyncResult);
                Stream streamResult = uploadUpdateState.AsyncResponse.GetResponseStream();
                StreamReader r = new StreamReader(streamResult);
                String responseString = r.ReadToEnd();
                Debug.WriteLine(responseString);
                LatestResponse = responseString;
            }
            catch (Exception e)
            {
                LatestResponse = "Failed";
            }
            
        }

        public bool shouldUpload()
        {
            if (LatestResponse == null || LatestResponse.Length == 0 || LatestResponse == "Failed")
                return true;
            else
                return false;
        }

        // TODO: Parse latest response to get the latest real search id.
        public string SearchId()
        {
            UploadResponseDictionary d = new UploadResponseDictionary();
            MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(LatestResponse));
            System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(d.GetType());
            d = serializer.ReadObject(ms) as UploadResponseDictionary;
            ms.Close();

            return d.d.id;
        }
    }
}
